package com.niiwoo.civet.trade.service.local.newRefund.callback;

import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.fastjson.JSONObject;
import com.niiwoo.civet.base.enums.DeadlineUnitEnum;
import com.niiwoo.civet.base.enums.FeeTypeEnum;
import com.niiwoo.civet.base.enums.RefundTypeEnum;
import com.niiwoo.civet.trade.dao.entity.*;
import com.niiwoo.civet.trade.dao.mapper.*;
import com.niiwoo.civet.trade.dto.PeriodAmountDTO;
import com.niiwoo.civet.trade.dto.PlanAmountDTO;
import com.niiwoo.civet.trade.dto.common.ProjectDynamicDTO;
import com.niiwoo.civet.trade.enums.BorrowerPlanRefundStatusEnum;
import com.niiwoo.civet.trade.enums.ProjectDynamicEnum;
import com.niiwoo.civet.trade.enums.ProjectSubStatusEnum;
import com.niiwoo.civet.trade.enums.RepayStatusEnum;
import com.niiwoo.civet.trade.service.local.newRefund.common.RefundCommonService;
import com.niiwoo.civet.trade.service.local.project.ProjectLocalService;
import com.niiwoo.civet.trade.utils.RepaymentUtil;
import com.niiwoo.civet.user.enums.CreditEnum;
import com.niiwoo.civet.user.service.UserCreditDubboService;
import com.niiwoo.tripod.provider.exception.BizException;
import lombok.extern.slf4j.Slf4j;
import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionSynchronizationAdapter;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.util.Assert;

import java.math.BigDecimal;
import java.util.*;
import java.util.Map.Entry;

/**
 * 还款回调-借款标的、借款人帐单维护 
 *
 * @author: yuanguang
 * @version 1.0.0
 */
@Slf4j
@Service
public class CallBackBorrowerLocalService {
	
    @Autowired
    private ProjectMapperExt projectMapperExt;
	
    @Autowired
    private ProjectBorrowerSummaryMapperExt projectBorrowerSummaryMapperExt;

    @Autowired
    private ProjectBorrowerPlanNewMapperExt projectBorrowerPlanNewMapperExt;    
    
    @Autowired
    private ProjectBorrowerPlanDetailMapperExt projectBorrowerPlanDetailMapperExt;
    
    @Autowired
    private ProjectLocalService projectLocalService;

    @Reference(version = "1.0.0")
    private UserCreditDubboService userCreditDubboService;
    @Autowired
	private RefundOrderDetailBizMapperExt refundOrderDetailBizMapperExt;

	@Autowired
	private RefundCommonService refundCommonService;

	/**
	 * 还款回调-出款方逻辑更新
	 * @param refundOrder
	 * @param summary
	 */
	@Transactional
    public void handleRefund(RefundOrder refundOrder, ProjectBorrowerSummary summary, List<String> detailRequestNoList, Project project){
		log.info("出款方数据更新开始:refundOrder={}", refundOrder);
		// 还款明细
		List<RefundOrderDetailBiz> bizList = refundOrderDetailBizMapperExt.queryRefundOrderDetailBizByDetailRequestNoList(detailRequestNoList);
    	if(bizList==null || bizList.size()==0){
			log.info("该订单没有明细需要处理,batchNo={}",refundOrder.getBatchNo());
			throw new BizException("该订单没有明细需要处理");
		}
		// 按期汇总还款费用明细
		Map<Integer, PeriodAmountDTO> bizMap = this.getBizMap(bizList);
		// 按期处理
		for (Entry<Integer, PeriodAmountDTO> entry : bizMap.entrySet()) {
			Integer currentPeriod = entry.getKey();
            PeriodAmountDTO periodAmountDTO = entry.getValue();
			// 还款计划
			ProjectBorrowerPlanNew planNew = projectBorrowerPlanNewMapperExt.selectByProjectAndPeriod(refundOrder.getProjectId(), currentPeriod);
			// 还款计划明细
			List<ProjectBorrowerPlanDetail> planDetails = projectBorrowerPlanDetailMapperExt.selectByPlanId(planNew.getId());
            // 处理还款计划
            this.updateBorrowerPlanData(refundOrder,periodAmountDTO, planNew, planDetails,summary.getCurrentPeriod(),project);
		}
		//更新摘要表和标的表,添加记录
		this.updateSummaryProjectAddRecord(refundOrder,summary);
		log.info("出款方数据更新结束:batchNo={}", refundOrder.getBatchNo());
    }

    private Map<Integer, PeriodAmountDTO> getBizMap(List<RefundOrderDetailBiz> bizList){
        Map<Integer, PeriodAmountDTO> bizMap = new LinkedHashMap<Integer, PeriodAmountDTO>();
        for (RefundOrderDetailBiz detailBiz : bizList) {
            PeriodAmountDTO amountDTO = bizMap.get(detailBiz.getCurrentPeriod());
            if (amountDTO == null) {
                amountDTO = new PeriodAmountDTO();
				bizMap.put(detailBiz.getCurrentPeriod(), amountDTO);
            }
            amountDTO.setCapital(amountDTO.getCapital().add(detailBiz.getCapital()));
            amountDTO.setInterest(amountDTO.getInterest().add(detailBiz.getInterest()));
            amountDTO.setPenalty(amountDTO.getPenalty().add(detailBiz.getPenaltyFee()));
            amountDTO.setGuarantee(amountDTO.getGuarantee().add(detailBiz.getGuaranteeFee()));
            amountDTO.setManage(amountDTO.getManage().add(detailBiz.getManageFee()));
			amountDTO.setConsultingFee(amountDTO.getConsultingFee().add(detailBiz.getConsultingFee()));
        }
        return bizMap;
    }
	/**
	 * 处理还款计划
	 * @param refundOrder
	 * @param periodAmountDTO
	 * @param planNew
	 * @param planDetails
	 * @param currentPeriod
	 * @return
	 */
	private void updateBorrowerPlanData(RefundOrder refundOrder, PeriodAmountDTO periodAmountDTO, ProjectBorrowerPlanNew planNew,
                                           List<ProjectBorrowerPlanDetail> planDetails, Integer currentPeriod,Project project) {
		// 更新还款计算明细
		PlanAmountDTO planAmountDTO = new PlanAmountDTO();
		for (ProjectBorrowerPlanDetail detail : planDetails) {
			if (FeeTypeEnum.CAPITAL.getValue().equals(detail.getFeeType())) {
				planAmountDTO.setCapital(detail.getMoney());
				planAmountDTO.setRefundCapital(detail.getRefundMoney().add(periodAmountDTO.getCapital()));
				this.updatePlanDetail(detail, periodAmountDTO.getCapital());
			} else if (FeeTypeEnum.INTEREST.getValue().equals(detail.getFeeType())) {
				planAmountDTO.setInterest(detail.getMoney());
				planAmountDTO.setRefundInterest(detail.getRefundMoney().add(periodAmountDTO.getInterest()));
				this.updatePlanDetail(detail, periodAmountDTO.getInterest());
			} else if (FeeTypeEnum.PENALTY.getValue().equals(detail.getFeeType())) {
				planAmountDTO.setPenaltyFee(detail.getMoney());
				planAmountDTO.setRefundPenaltyFee(detail.getRefundMoney().add(periodAmountDTO.getPenalty()));
				this.updatePlanDetail(detail, periodAmountDTO.getPenalty());
			} else if (FeeTypeEnum.MANAGEMENT_FEE.getValue().equals(detail.getFeeType())) {
				planAmountDTO.setManagerFee(detail.getMoney());
				planAmountDTO.setRefundManagerFee(detail.getRefundMoney().add(periodAmountDTO.getManage()));
				this.updatePlanDetail(detail, periodAmountDTO.getManage());
			} else if (FeeTypeEnum.GUARANTEE_FEE.getValue().equals(detail.getFeeType())) {
				planAmountDTO.setGuaranteeFee(detail.getMoney());
				planAmountDTO.setRefundGuaranteeFee(detail.getRefundMoney().add(periodAmountDTO.getGuarantee()));
				this.updatePlanDetail(detail, periodAmountDTO.getGuarantee());
			} else if (FeeTypeEnum.CONSULTING_FEE.getValue().equals(detail.getFeeType())) {
				planAmountDTO.setConsultingFee(detail.getMoney());
				planAmountDTO.setRefundConsultingFee(detail.getRefundMoney().add(periodAmountDTO.getConsultingFee()));
				this.updatePlanDetail(detail, periodAmountDTO.getConsultingFee());
			}
		}

		Boolean isFinishedOnePeriod = false;
		// 判断当期是否结清
		if(refundOrder.getRefundType().equals(RefundTypeEnum.OVERDEPT.getRefundType())){
			isFinishedOnePeriod = true;
		}else{
			if (planAmountDTO.getCapital().equals(planAmountDTO.getRefundCapital())
					&& planAmountDTO.getPenaltyFee().equals(planAmountDTO.getRefundPenaltyFee())
					&& planAmountDTO.getManagerFee().equals(planAmountDTO.getRefundManagerFee())
					&& planAmountDTO.getGuaranteeFee().equals(planAmountDTO.getRefundGuaranteeFee())
					&& planAmountDTO.getConsultingFee().equals(planAmountDTO.getRefundConsultingFee())) {
				if (planAmountDTO.getInterest().equals(planAmountDTO.getRefundInterest())) {
					isFinishedOnePeriod = true;
				} else {
					if (refundOrder.getRepayStatus().equals(RepayStatusEnum.BADLOANS.getCode())) {
						if (planNew.getPeriod() > currentPeriod + 1) {
							isFinishedOnePeriod = true;
						}
					}
				}
			}
		}

		if(isFinishedOnePeriod){
			ProjectBorrowerPlanNew planUpdater = new ProjectBorrowerPlanNew();
			planUpdater.setId(planNew.getId());
			planUpdater.setStatus(this.getPlanRefundStatusEnum(refundOrder,planNew,project).getCode());
			planUpdater.setOverDate(new Date());
			planUpdater.setOverCurrentDate(refundOrder.getCurrentDate());
			planUpdater.setUpdateTime(new Date());
			projectBorrowerPlanNewMapperExt.updateByPrimaryKeySelective(planUpdater);
		}

		// 如果是按日计息还款，更新还款计划状态，结清日期等
		if(refundCommonService.isCalculateInterestByDay(project.getOrgId(), project.getDeadlineUnit(), planNew.getRefundDate(), refundOrder.getCurrentDate())){
			ProjectBorrowerPlanNew planUpdater = new ProjectBorrowerPlanNew();
			planUpdater.setId(planNew.getId());
			planUpdater.setStatus(BorrowerPlanRefundStatusEnum.OVER_DEBT_REPAYMENT.getCode());
			planUpdater.setOverDate(new Date());
			planUpdater.setOverCurrentDate(refundOrder.getCurrentDate());
			planUpdater.setUpdateTime(new Date());
			projectBorrowerPlanNewMapperExt.updateByPrimaryKeySelective(planUpdater);
		}
	}

    /**
     * 更新摘要表和标的表,添加记录
     * @param refundOrder
     * @param summary
     */
	private void updateSummaryProjectAddRecord(RefundOrder refundOrder, ProjectBorrowerSummary summary){
		ProjectBorrowerSummary summaryUpdate = new ProjectBorrowerSummary();
		summaryUpdate.setProjectId(summary.getProjectId());
		summaryUpdate.setRefundedCorpus(summary.getRefundedCorpus().add(refundOrder.getCapital()));
		summaryUpdate.setRefundedInterest(summary.getRefundedInterest().add(refundOrder.getInterest()));
		summaryUpdate.setRefundedPenaltyFee(summary.getRefundedPenaltyFee().add(refundOrder.getPenaltyFee()));
		summaryUpdate.setRefundedGuaranteeFee(summary.getRefundedGuaranteeFee().add(refundOrder.getGuaranteeFee()));
		summaryUpdate.setRefundedManagementFee(summary.getRefundedManagementFee().add(refundOrder.getManageFee()));
		summaryUpdate.setRefundedConsultingFee(summary.getRefundedConsultingFee().add(refundOrder.getConsultingFee()));

		Project projectUpdate = new Project();
		projectUpdate.setProjectId(refundOrder.getProjectId());
		//提前结清
		if(RefundTypeEnum.OVERDEPT.getRefundType().equals(refundOrder.getRefundType())){
			summaryUpdate.setRepayStatus(RepayStatusEnum.SETTLEMENT.getCode());
			summaryUpdate.setOverTime(new Date());

			projectUpdate.setSubStatus(ProjectSubStatusEnum.FINISH_ADVANCE.getSubStatus());
			projectUpdate.setStatus(ProjectSubStatusEnum.FINISH_ADVANCE.getParentStatusEnum().getStatus());

			this.addProjectRecord(refundOrder, ProjectDynamicEnum.REPAYING_OVERDEPT_TEMPLATE, true);
			this.addProjectRecord(refundOrder, ProjectDynamicEnum.FINISH_ADVANCE, false);
		}else{
			ProjectBorrowerPlanNew planNext = projectBorrowerPlanNewMapperExt.selectNextNotRefunPeriod(refundOrder.getProjectId());
			if(RepayStatusEnum.BADLOANS.getCode().equals(refundOrder.getRepayStatus())){
				//坏账还款
				if(planNext==null){
					summaryUpdate.setRepayStatus(RepayStatusEnum.SETTLEMENT.getCode());
					summaryUpdate.setOverTime(new Date());

					projectUpdate.setSubStatus(ProjectSubStatusEnum.FINISH_BAD.getSubStatus());
					projectUpdate.setStatus(ProjectSubStatusEnum.FINISH_BAD.getParentStatusEnum().getStatus());

					this.addProjectRecord(refundOrder, ProjectDynamicEnum.REPAYING_BAD_TEMPLATE, true);
					this.addProjectRecord(refundOrder, ProjectDynamicEnum.FINISH_OVERDUE, false);
				}else{
					this.addProjectRecord(refundOrder, ProjectDynamicEnum.REPAYING_BAD_TEMPLATE, true);
				}
			}else{
				//正常、逾期还款
				summaryUpdate.setPreviousRefundDate(summary.getRefundDate());
				if(planNext!=null){
					RepayStatusEnum targetRepayStatus = null;
					if (RepaymentUtil.getOverdueDay(refundOrder.getCurrentDate(), planNext.getRefundDate()) > 0) {
						targetRepayStatus = RepayStatusEnum.NORMAL;
						summaryUpdate.setRepayStatus(targetRepayStatus.getCode());
					}
					summaryUpdate.setRefundDate(planNext.getRefundDate());
					summaryUpdate.setCurrentPeriod(planNext.getPeriod());
					summaryUpdate.setAutoRefundDate(planNext.getRefundDate());

					if(RepayStatusEnum.NORMAL.getCode().equals(refundOrder.getRepayStatus())){
						this.addProjectRecord(refundOrder, ProjectDynamicEnum.REPAYING_NORMAL_TEMPLATE, true);
					}else{
						if(targetRepayStatus!=null && targetRepayStatus == RepayStatusEnum.NORMAL){
							projectUpdate.setSubStatus(ProjectSubStatusEnum.REPAYING_INIT.getSubStatus());
							projectUpdate.setStatus(ProjectSubStatusEnum.REPAYING_INIT.getParentStatusEnum().getStatus());
						}
						this.addProjectRecord(refundOrder, ProjectDynamicEnum.REPAYING_OVERDUE_TEMPLATE, true);
					}
				}else{
					summaryUpdate.setRepayStatus(RepayStatusEnum.SETTLEMENT.getCode());
					summaryUpdate.setOverTime(new Date());

					if(RepayStatusEnum.NORMAL.getCode().equals(refundOrder.getRepayStatus())){
						// 查询历史逾期期数
						Integer overdueNum = projectBorrowerPlanNewMapperExt.countOverdueNums(refundOrder.getBorrowUserId(), refundOrder.getProjectId());
						if(overdueNum>0){
							projectUpdate.setSubStatus(ProjectSubStatusEnum.FINISH_OVERDUE.getSubStatus());
							projectUpdate.setStatus(ProjectSubStatusEnum.FINISH_OVERDUE.getParentStatusEnum().getStatus());
						}else{
							projectUpdate.setSubStatus(ProjectSubStatusEnum.FINISH_NORMAL.getSubStatus());
							projectUpdate.setStatus(ProjectSubStatusEnum.FINISH_NORMAL.getParentStatusEnum().getStatus());
						}

						this.addProjectRecord(refundOrder, ProjectDynamicEnum.REPAYING_NORMAL_TEMPLATE, true);
						this.addProjectRecord(refundOrder, ProjectDynamicEnum.FINISH_NORMAL, false);
					}else{

						projectUpdate.setSubStatus(ProjectSubStatusEnum.FINISH_OVERDUE.getSubStatus());
						projectUpdate.setStatus(ProjectSubStatusEnum.FINISH_OVERDUE.getParentStatusEnum().getStatus());

						this.addProjectRecord(refundOrder, ProjectDynamicEnum.REPAYING_OVERDUE_TEMPLATE, true);
						this.addProjectRecord(refundOrder, ProjectDynamicEnum.FINISH_OVERDUE, false);
					}
				}
			}
		}
		summaryUpdate.setUpdateTime(new Date());
		log.info("更新摘要表数据,summaryUpdate={}", JSONObject.toJSONString(summaryUpdate));
		projectBorrowerSummaryMapperExt.updateByPrimaryKeySelective(summaryUpdate);

		if(projectUpdate.getSubStatus()!=null){
			projectUpdate.setUpdateTime(new Date());
			log.info("更新标的表数据,projectUpdate={}", JSONObject.toJSONString(projectUpdate));
			projectMapperExt.updateByPrimaryKeySelective(projectUpdate);

			TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
				@Override
				public void afterCommit() {
					super.afterCommit();
					try {
						log.info("userCreditDubboService.changeCreditNeedUpdate--userId={}",refundOrder.getBorrowUserId());
						userCreditDubboService.changeCreditNeedUpdate(refundOrder.getBorrowUserId(), CreditEnum.CreditAmountType.SPEED_BORROW);
					}catch (Exception e){
						log.error("userCreditDubboService.changeCreditNeedUpdate() error",e);
					}
				}
			});
		}
	}
    
	/**
	 * 更新还款详情记录
	 * 
	 * @param detail
	 * @param refundMoney
	 */
	private void updatePlanDetail(ProjectBorrowerPlanDetail detail, BigDecimal refundMoney) {
		if(refundMoney.compareTo(BigDecimal.ZERO)==0){
			return;
		}
		ProjectBorrowerPlanDetail detailUpdate = new ProjectBorrowerPlanDetail();
		detailUpdate.setId(detail.getId());
		detailUpdate.setRefundMoney(detail.getRefundMoney().add(refundMoney));
		detailUpdate.setUpdateTime(new Date());
		projectBorrowerPlanDetailMapperExt.updateByPrimaryKeySelective(detailUpdate);
	}
	
	/**
	 * 添加项目操作动态记录
	 * 
	 * @param refundOrder
	 * @param projectDynamicEnum
	 * @param hasFeeDetail
	 */
	private void addProjectRecord(RefundOrder refundOrder, ProjectDynamicEnum projectDynamicEnum, boolean hasFeeDetail) {
		Assert.notNull(refundOrder,"订单不可空");
		ProjectDynamicDTO dto = new ProjectDynamicDTO();
		dto.setProjectId(refundOrder.getProjectId());
		Long refundOrderId = refundOrder.getId();
		dto.setRelationId(refundOrderId);
		dto.setTradeTypeEnum(ProjectDynamicDTO.TradeTypeEnum.REPAYMENT);
		dto.setProjectDynamicEnum(projectDynamicEnum);
		dto.setUserId(refundOrder.getBorrowUserId());
		if (hasFeeDetail) {
			List<String> paramsList = new ArrayList<>();
			paramsList.add((refundOrder.getGuaranteeFee().add(refundOrder.getManageFee())
					.add(refundOrder.getPenaltyFee()).add(refundOrder.getInterest()).add(refundOrder.getCapital())).toString());
			StringBuilder stringBuffer = new StringBuilder();
			stringBuffer.append("本金").append(refundOrder.getCapital()).append("元,");
			stringBuffer.append("利息").append(refundOrder.getInterest()).append("元,");
			if (refundOrder.getManageFee().compareTo(BigDecimal.ZERO) > 0) {
				stringBuffer.append("平台管理费").append(refundOrder.getManageFee()).append("元,");
			}
			if (refundOrder.getGuaranteeFee().compareTo(BigDecimal.ZERO) > 0) {
				stringBuffer.append("担保服务费").append(refundOrder.getGuaranteeFee()).append("元,");
			}
			if (refundOrder.getPenaltyFee().compareTo(BigDecimal.ZERO) > 0) {
				stringBuffer.append("罚息").append(refundOrder.getPenaltyFee()).append("元,");
			}
			String str = stringBuffer.toString();
			paramsList.add(str.substring(0, str.length() - 1));
			dto.setParamsList(paramsList);
		}
		projectLocalService.addProjectDynamicRecord(dto);
	}	
	
    private BorrowerPlanRefundStatusEnum getPlanRefundStatusEnum(RefundOrder refundOrder,ProjectBorrowerPlanNew planNew,Project project){
		BorrowerPlanRefundStatusEnum statusEnum = null;
		if(planNew.getRefundDate().after(new DateTime(refundOrder.getCurrentDate()).plusMonths(1).minusDays(1).toDate())
				&& project.getDeadlineUnit().equals(DeadlineUnitEnum.BY_MONTH.getDeadlineUnit())
				&& planNew.getPeriod()!=1){
			statusEnum = BorrowerPlanRefundStatusEnum.OVER_DEBT_REPAYMENT;
		}else if(RepaymentUtil.getOverdueDay(planNew.getRefundDate(),refundOrder.getCurrentDate())>0){
			statusEnum = BorrowerPlanRefundStatusEnum.OVERDUE_REPAYMENT;
		}else{
			statusEnum = BorrowerPlanRefundStatusEnum.NORMAL_REPAYMENT;
		}
		return statusEnum;
    }
}